package material

import (
	"context"
	"device-admin/config/mysql"
	"device-admin/internal/app/grpc/client"
	"device-admin/internal/app/grpc/protoc/system_admin"
	"device-admin/internal/dao"
	"device-admin/internal/define"
	"device-admin/internal/models"
	"path"
	"strings"
	"unicode/utf8"

	"192.168.1.75/go-pkg/errorx"
	"192.168.1.75/go-pkg/logx"
)

const (
	TEXT  = iota + 1 // 文本语音
	VOICE            // 音频语音
	EMOJI            // 情绪表情
	LIGHT            // 灯光素材
)

type Material struct{}

// 新建素材
// Type 1文案语音 2音频语音 3情绪表情 4灯光素材
func (Material) Add(ctx context.Context, merchantID, userID, username string, Type int, name, content, filePath, folderID string) (err error) {
	db := mysql.NewDB()
	var MaterialID int64
	if Type != TEXT && Type != VOICE && Type != EMOJI {
		return errorx.New("素材类型错误", -1)
	}
	if folderID == "" {
		return errorx.New("分组不能为空", -1)
	}
	if Type == TEXT { // 文案语音 Content 10000+
		// 语音内容校验
		if strings.TrimSpace(content) == "" {
			err = errorx.New("语音内容不能为空", -1)
			return
		}
		if utf8.RuneCountInString(strings.TrimSpace(content)) > 30 {
			err = errorx.New("语音内容不等超过20字符", -1)
			return
		}
		name = ""
		content = strings.TrimSpace(content)
		filePath = ""
		MaterialID = dao.Material{}.GetNextMaterialID(ctx, db, merchantID, TEXT)
	} else if Type == VOICE { // 音频语音 FilePath 10000+
		if strings.TrimSpace(filePath) == "" {
			return errorx.New("音频语音文件不能为空", -1)
		}
		if !strings.HasSuffix(path.Ext(filePath), ".wav") {
			return errorx.New("音频语音文件格式错误", -1)
		}
		// 文件确认
		systemAdmin, err := client.GetSystemAdminClient()
		if err != nil {
			return errorx.New("系统出错", -1)
		}
		res, _ := systemAdmin.ConfirmFile(context.Background(), &system_admin.ConfirmFileReq{FileUrl: filePath})
		if res.Code != 0 {
			return errorx.New("系统出错", -1)
		}
		name = ""
		content = path.Base(filePath)
		filePath = res.FileUrl
		MaterialID = dao.Material{}.GetNextMaterialID(ctx, db, merchantID, VOICE)
	} else if Type == EMOJI { // 情绪表情 name filePath 40000+
		if strings.TrimSpace(name) == "" {
			err = errorx.New("表情名称不能为空", -1)
			return
		}
		if utf8.RuneCountInString(strings.TrimSpace(name)) > 6 {
			err = errorx.New("表情名称不能超过6个字符", -1)
			return
		}

		if strings.TrimSpace(filePath) == "" {
			return errorx.New("表情语音文件不能为空", -1)
		}
		if !strings.HasSuffix(path.Ext(filePath), ".gif") && !strings.HasSuffix(path.Ext(filePath), ".GIF") {
			err = errorx.New("表情文件格式错误", -1)
			return
		}
		// 文件确认
		systemAdmin, err := client.GetSystemAdminClient()
		if err != nil {
			return errorx.New("系统出错", -1)
		}
		res, _ := systemAdmin.ConfirmFile(context.Background(), &system_admin.ConfirmFileReq{FileUrl: filePath})
		if res.Code != 0 {
			return errorx.New("系统出错", -1)
		}
		name = strings.TrimSpace(name)
		content = ""
		filePath = res.FileUrl
		MaterialID = dao.Material{}.GetNextMaterialID(ctx, db, merchantID, EMOJI)
	}

	if folderID != "0" {
		// 查询分组是否存在
		var folderType int8
		if Type == TEXT || Type == VOICE {
			folderType = 1 // 语音
		} else if Type == EMOJI {
			folderType = 2 // 表情
		}
		folderInfo, _ := dao.MaterialFolder{}.Detail(ctx, db, merchantID, folderID, folderType)
		if folderInfo == nil || folderInfo.ID == "" {
			return errorx.New("分组不存在", -1)
		}
	}
	dao.Material{}.Create(ctx, db, merchantID, MaterialID, strings.TrimSpace(name), strings.TrimSpace(content),
		strings.TrimSpace(filePath), userID, username, folderID, Type, 1, 0)
	return nil
}

// 素材列表
// type: 1文案语音 2音频语音 3表情 4灯光
func (Material) List(ctx context.Context, merchantID, userID, username string, keywords string, Type, status int, folderID string, page, limit int) (data []*models.Material, total int64, err error) {
	db := mysql.NewDB()
	if Type != 1 && Type != 3 && Type != 4 {
		err = errorx.New("素材类型错误", -1)
		return
	}

	// 自动写入默认素材
	_, Count := dao.Material{}.Detail(ctx, db, merchantID, "", "", Type, 0, -1)
	if Count == 0 {
		if Type == 1 {
			for _, v := range define.MaterialVoice {
				dao.Material{}.Create(ctx, db, merchantID, v.ID, v.Name, v.Content, v.FilePath, userID, username, "0", Type, 1, 1)
			}
		} else if Type == 3 {
			for _, v := range define.MaterialEmoji {
				dao.Material{}.Create(ctx, db, merchantID, v.ID, v.Name, v.Content, v.FilePath, userID, username, "0", Type, 1, 1)
			}
		} else if Type == 4 {
			for _, v := range define.MaterialLight {
				dao.Material{}.Create(ctx, db, merchantID, v.ID, v.Name, v.Content, "", userID, username, "0", Type, 1, 1)
			}
		}
	}
	var materialType interface{}
	if Type == 1 { // 查所有时的"1"代表"1,2"两种语音
		materialType = []int{1, 2}
	} else {
		materialType = Type
	}
	auditStatus := -1
	if status == 1 { // Status = 0 查所有 ,Status = 1查可用
		auditStatus = 1 // 审核通过
	}
	data, total, _ = dao.Material{}.List(ctx, db, merchantID, keywords, materialType, status, auditStatus, folderID, page, limit)
	return
}

// 启用禁用
func (Material) ChangeStatus(ctx context.Context, merchantID, ID string, status int) (err error) {
	db := mysql.NewDB()
	if ID == "" {
		return errorx.New("素材ID不能为空", -1)
	}
	if status != 1 && status != 2 {
		return errorx.New("禁用启用状态错误", -1)
	}
	_, count := dao.Material{}.Detail(ctx, db, merchantID, ID, "", 0, 3-status, -1)
	if count == 0 {
		return errorx.New("素材不存在", -1)
	}
	dao.Material{}.ChangeStatus(ctx, db, merchantID, ID, status)
	return
}

// 素材移动分组
func (Material) ChangeFolder(ctx context.Context, merchantID, ID string, folderID string) (err error) {
	db := mysql.NewDB()
	if ID == "" {
		return errorx.New("素材ID不能为空", -1)
	}
	// 素材校验
	materialDetail, count := dao.Material{}.Detail(ctx, db, merchantID, ID, "", 0, 0, -1)
	if count == 0 {
		return errorx.New("素材不存在", -1)
	}
	// 分组校验
	if folderID != "0" {
		var folderType int8
		if materialDetail.Type == 1 || materialDetail.Type == 2 {
			folderType = 1 // 语音
		} else if materialDetail.Type == 3 {
			folderType = 2 // 表情
		} else if materialDetail.Type == 4 {
			folderType = 3 // 灯光
		}
		folderInfo, _ := dao.MaterialFolder{}.Detail(ctx, db, merchantID, folderID, folderType)
		if folderInfo == nil || folderInfo.ID == "" {
			return errorx.New("分组不存在", -1)
		}
	}
	// 移动分组
	dao.Material{}.ChangeFolder(ctx, db, merchantID, ID, folderID)
	return
}

type AuditList struct {
	models.Material
	MerchantName string `gorm:"-" json:"merchant_name"` // 创建商户名称
}

// 素材审核列表
func (Material) AuditList(ctx context.Context, merchantID, userID string, Page, Limit int) (data []AuditList, total int64, err error) {
	db := mysql.NewDB()
	if merchantID != "1" {
		return data, total, errorx.New("非管理员用户无权限", -1)
	}
	data = []AuditList{}
	list, total, _ := dao.Material{}.List(ctx, db, "", "", 0, 0, 0, "", Page, Limit)
	// 商户名称
	systemAdminClient, err := client.GetSystemAdminClient()
	if err != nil {
		return data, total, errorx.New("系统出错", -1)
	}

	var req system_admin.MerchantListReq
	req.UserId = userID
	merchantList, merchantErr := systemAdminClient.MerchantList(context.Background(), &req)
	if merchantErr != nil {
		logx.Error(context.Background(), "grpc 获取商户信息错误", logx.String("err", merchantErr.Error()))
		return data, total, errorx.New("系统出错", -1)
	}

	MerchantIDNameMap := make(map[string]string) // id => name
	for _, v := range merchantList.List {
		MerchantIDNameMap[v.MerchantId] = v.MerchantName
	}
	for _, v := range list {
		var merchantName string
		if _, ok := MerchantIDNameMap[v.MerchantID]; ok {
			merchantName = MerchantIDNameMap[v.MerchantID]
		} else if v.MerchantID == "1" {
			merchantName = "admin"
		}
		data = append(data, AuditList{Material: *v, MerchantName: merchantName})
	}
	return
}

// 素材审核
func (Material) Audit(ctx context.Context, merchantID, UserID, UserName, ID string, AuditStatus int) (err error) {
	db := mysql.NewDB()
	if merchantID != "1" {
		return errorx.New("非管理员用户无权限", -1)
	}
	if ID == "" {
		return errorx.New("素材ID不能为空", -1)
	}
	if AuditStatus != 1 && AuditStatus != 2 { // 1审核通过 2审核拒绝
		return errorx.New("审核状态错误", -1)
	}
	materialInfo, count := dao.Material{}.Detail(ctx, db, "", ID, "", 0, 0, 0) // 未审核
	if count == 0 || materialInfo == nil {
		return errorx.New("素材不存在", -1)
	}
	if materialInfo.AuditStatus == AuditStatus {
		return errorx.New("审核状态错误", -1)
	}

	// 素材审核
	dao.Material{}.Audit(ctx, db, ID, AuditStatus)
	// 写入素材审核记录表
	dao.MaterialAuditLog{}.Create(ctx, db, ID, materialInfo.MerchantID, UserID, UserName, AuditStatus)
	return
}

// 素材审核记录
func (Material) AuditLog(ctx context.Context, merchantID string, UserID string, Page, Limit int) (data []dao.AuditLogList, total int64, err error) {
	if merchantID != "1" {
		return data, total, errorx.New("非管理员用户无权限", -1)
	}
	db := mysql.NewDB()
	data, total, _ = dao.MaterialAuditLog{}.List(ctx, db, Page, Limit)

	systemAdminClient, err := client.GetSystemAdminClient()
	if err != nil {
		return data, total, errorx.New("系统出错", -1)
	}

	var req system_admin.MerchantListReq
	req.UserId = UserID
	merchantList, merchantErr := systemAdminClient.MerchantList(context.Background(), &req)
	if merchantErr != nil {
		logx.Error(context.Background(), "grpc 获取商户信息错误", logx.String("err", merchantErr.Error()))
		return data, total, errorx.New("系统出错", -1)
	}

	MerchantIDNameMap := make(map[string]string) // id => name
	for _, v := range merchantList.List {
		MerchantIDNameMap[v.MerchantId] = v.MerchantName
	}
	// 创建商户名称 审核商户名称
	for k, v := range data {
		if v.Type == 3 {
			data[k].Content = v.Name
		}
		if v.MerchantID == "1" {
			data[k].MerchantName = "admin"
		} else {
			if _, ok := MerchantIDNameMap[v.MerchantID]; ok {
				data[k].MerchantName = MerchantIDNameMap[v.MerchantID]
			}
		}
		if v.AuditMerchantID == "1" {
			data[k].AuditMerchantName = "admin"
		} else {
			if _, ok := MerchantIDNameMap[v.AuditMerchantID]; ok {
				data[k].AuditMerchantName = MerchantIDNameMap[v.AuditMerchantID]
			}
		}
	}
	return
}
